# include "vd.h"

# include "VD_CloseFile.c"
# include "VD_OpenFile.c"
# include "VD_ThreadHandler.c"
# include "VD_DeviceControl.c"
# include "VD_CreateDevice.h"
//# include "VD_CheckFile.h"
# include "VD_CreateClose.c"
# include "VD_Unload.c"
# include "VD_ReadWrite.c"
# include "VD_PnP.h"

#pragma code_seg("INIT")

NTSTATUS DriverEntry (
    IN PDRIVER_OBJECT   DriverObject,
    IN PUNICODE_STRING  RegistryPath
    )
{
	NTSTATUS						status;
    UNICODE_STRING					device_dir_name;
    UNICODE_STRING					Master_device_name;
	UNICODE_STRING					Master_sym_link;
	PDEVICE_EXTENSION				device_extension;

	OBJECT_ATTRIBUTES				object_attributes;
	WCHAR							device_name_buffer[MAXIMUM_FILENAME_LENGTH];
	PDEVICE_OBJECT					device_object;
	USHORT							i;

	RegPathW.Length = RegistryPath->Length;
	RegPathW.MaximumLength = RegistryPath->MaximumLength;
	RegPathW.Buffer = (PWCHAR)ExAllocatePoolWithTag(
												NonPagedPool,
												RegistryPath->MaximumLength + sizeof(WCHAR),
												POOL_TAG
												);
	
	if (RegPathW.Buffer == 0)
	{
		DbgPrint("Unable to allocate memory for RegPath \n");
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	RtlCopyMemory(
				RegPathW.Buffer,
				RegistryPath->Buffer,
				RegistryPath->Length
				);
	
	RegPathW.Buffer[RegistryPath->Length/sizeof(WCHAR)]= L'\0';
			
    RtlInitUnicodeString(&device_dir_name, DEVICE_DIR_NAME);
	
    InitializeObjectAttributes(
							&object_attributes,
							&device_dir_name,
							OBJ_PERMANENT,
							NULL,
							NULL
							);
	
    status = ZwCreateDirectoryObject(
									&dir_handle,
									DIRECTORY_ALL_ACCESS,
									&object_attributes
									);

    if (!NT_SUCCESS(status))
    {
		DbgPrint("Unable to create Directory \n");
		return status;
    }

    ZwMakeTemporaryObject(dir_handle);
    
    RtlInitUnicodeString(&Master_device_name, MASTER_DEVICE_NAME);

	status = IoCreateDevice(
						  DriverObject,
						  sizeof(DEVICE_EXTENSION),
						  &Master_device_name,
						  DEVICE_MULTI_VDD,
						  0,
						  FALSE,
						  &device_object
						   );

	if (!NT_SUCCESS(status))
    {
        DbgPrint("Unable to create Device \n");
		ZwClose(dir_handle);
		ExFreePoolWithTag(RegPathW.Buffer,POOL_TAG);
        return status;
    }
	device_extension = (PDEVICE_EXTENSION)device_object->DeviceExtension;
	device_extension->DeviceNumber = BaseDeviceNumber;

//Create Master Symlink
	RtlInitUnicodeString(&Master_sym_link, MULTI_VDD_SYMLINK_NAME);
	status = IoCreateUnprotectedSymbolicLink(&Master_sym_link, &Master_device_name);
	
	if (!NT_SUCCESS(status))
    {
        DbgPrint("Unable to create SymLink (%x) \n", status);
		ExFreePoolWithTag(RegPathW.Buffer,POOL_TAG);
		ZwClose(dir_handle);
        return status;
    }

	DriverObject->MajorFunction[IRP_MJ_CREATE] = VD_CreateClose;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = VD_CreateClose;
    DriverObject->MajorFunction[IRP_MJ_READ] = VD_ReadWrite;
    DriverObject->MajorFunction[IRP_MJ_WRITE] = VD_ReadWrite;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VD_DeviceControl;
	DriverObject->MajorFunction[IRP_MJ_PNP] = VD_PnP;	

    DriverObject->DriverUnload = VD_Unload;

    BaseDriverObject = DriverObject;
	
	//Initialize Status of Disk Devices
	for (i = 0; i <= NumberOfDevices; i++)
		DiskDeviceStatus[i] = L'0';
	
	//Write DiskStatus to Register
	status =  RtlWriteRegistryValue(
								  RTL_REGISTRY_ABSOLUTE,
								  RegPathW.Buffer,
								  REG_DISK_DEVICE_STATUS,
								  REG_SZ,
								  DiskDeviceStatus,
								  (sizeof(DiskDeviceStatus))
								   );

	if (!NT_SUCCESS(status))
		DbgPrint("Disk status not written to register %x \n",status);

	return STATUS_SUCCESS;
}